package com.jerei.web.utils;

import com.github.zafarkhaja.semver.Version;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.jerei.utils.UtilsProperties;
import okhttp3.Call;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ro.fortsoft.pf4j.PluginManager;
import ro.fortsoft.pf4j.PluginWrapper;
import ro.fortsoft.pf4j.update.UpdateManager;
import ro.fortsoft.pf4j.update.UpdateRepository;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;

/**
 * Created by sunfeihu on 2016/11/29.
 */
public class UtilsPluginUpdateManager extends UpdateManager {

    private static final Logger log = LoggerFactory.getLogger(UtilsPluginUpdateManager.class);

    public UtilsPluginUpdateManager(PluginManager pluginManager) {
        super(pluginManager);
    }

    @Override
    public List<UpdateRepository.PluginInfo> getAvailablePlugins() {
        return super.getAvailablePlugins();
    }

    @Override
    public boolean hasAvailablePlugins() {
        return super.hasAvailablePlugins();
    }

    @Override
    public List<UpdateRepository.PluginInfo> getUpdates() {
        List<UpdateRepository.PluginInfo> updates = new ArrayList<UpdateRepository.PluginInfo>();
        List<UpdateRepository.PluginInfo> plugins = getPlugins();
        for (UpdateRepository.PluginInfo pluginInfo : plugins) {
            PluginWrapper installedPlugin = pluginManager.getPlugin(pluginInfo.id);
            if (installedPlugin != null) {
                Version installedVersion = installedPlugin.getDescriptor().getVersion();
                if (pluginInfo.hasUpdate(this.lastVersion(pluginInfo), installedVersion)) {
                    updates.add(pluginInfo);
                }
            }
        }
        return updates;
    }

    /**
     * 获取最新版本
     *
     * @return 最新版本
     */
    public Version lastVersion(UpdateRepository.PluginInfo pluginInfo) {
        if (null != pluginInfo.releases && pluginInfo.releases.size() > 0) {
            ArrayList<Version> versions = new ArrayList<Version>();
            for (UpdateRepository.PluginRelease pluginRelease : pluginInfo.releases) {
                versions.add(Version.valueOf(pluginRelease.version));
            }
            if (null != versions && versions.size() > 0) {
                return versions.get(versions.size() - 1);
            }
        }
        return Version.forIntegers(0, 0, 0);
    }

    @Override
    public boolean hasUpdates() {
        List<UpdateRepository.PluginInfo> plugins = getPlugins();
        for (UpdateRepository.PluginInfo pluginInfo : plugins) {
            PluginWrapper installedPlugin = pluginManager.getPlugin(pluginInfo.id);
            if (installedPlugin != null) {
                Version installedVersion = installedPlugin.getDescriptor().getVersion();
                if (pluginInfo.hasUpdate(this.lastVersion(pluginInfo), installedVersion)) {
                    return true;
                }
            }
        }
        return false;
    }

    @Override
    public List<UpdateRepository.PluginInfo> getPlugins() {
        List<UpdateRepository.PluginInfo> plugins = new ArrayList<UpdateRepository.PluginInfo>();
        List<UpdateRepository> repositories = getRepositories();
        List<UpdateRepository.PluginRelease> pluginReleaseList = null;
        for (UpdateRepository repository : repositories) {
            try {
                OkHttpClient client = new OkHttpClient();
                Request request = new Request.Builder()
                        .url(repository.getUrl() + "/plugins")
                        .build();
                Request.Builder result = request.newBuilder();
                client.cookieJar().loadForRequest(request.url());
                Call call = client.newCall(request);
                Response response = call.execute();
                String jsonStr = "";
                if (response.code() == 200) {
                    jsonStr = response.body().string();
                    Gson gson = new GsonBuilder().create();
                    UpdateRepository.PluginInfo[] items = gson.fromJson(jsonStr, UpdateRepository.PluginInfo[].class);
                    //为插件更新地址拼接前缀
                    if (null != items && items.length > 0) {
                        for (int i = 0; i < items.length; i++) {
                            pluginReleaseList = items[i].releases;
                            if (null != pluginReleaseList && pluginReleaseList.size() > 0) {
                                for (UpdateRepository.PluginRelease pluginRelease : pluginReleaseList) {
                                    pluginRelease.url = repository.getUrl() + "/" + pluginRelease.url;
                                }
                            }
                        }
                        plugins.addAll(Arrays.asList(items));
                    }
                }
            } catch (Exception e) {
                if (log.isErrorEnabled()) {
                    log.error("远程插件服务器异常，远程服务器地址为：" + repository.getUrl(), e);
                }
            }
        }
        return plugins;
    }

    @Override
    public List<UpdateRepository> getRepositories() {
        List<UpdateRepository> list = new ArrayList<UpdateRepository>();
        String updateUrl = UtilsProperties.getInstance().getProperty("plugin.update.url");
        if (!"".equals(updateUrl)) {
            String[] updateUrlArr = updateUrl.split(",");
            if (null != updateUrlArr && updateUrlArr.length > 0) {
                for (int i = 0; i < updateUrlArr.length; i++) {
                    list.add(new UpdateRepository(UUID.randomUUID().toString(), updateUrlArr[i]));
                }
            }
        }
        return list;
    }

    @Override
    public synchronized void refresh() {
        super.refresh();
    }

    @Override
    public synchronized boolean installPlugin(String url) {
        return super.installPlugin(url);
    }

    public boolean updatePlugin(String id, String url, String pluginBasePath) throws IOException {
        //先下载插件
        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder().url(url).build();
        Response response = client.newCall(request).execute();
        if (response.code() == 200) {
            //先停用插件
            UtilsPluginManager.get().stopPlugin(id);
            //再删除插件
            UtilsPluginManager.get().deletePlugin(id);
            InputStream is = response.body().byteStream();
            byte[] buf = new byte[2048];
            int len = 0;
            long total = response.body().contentLength();
            File file = new File(pluginBasePath, url.substring(url.lastIndexOf("/")));
            FileOutputStream fos = new FileOutputStream(file);
            while ((len = is.read(buf)) != -1) {
                fos.write(buf, 0, len);
            }
            fos.flush();
            is.close();
            fos.close();
            //插件下载和写入成功以后，加载插件
            UtilsPluginManager.get().loadPlugin(file);
            //启动插件
            UtilsPluginManager.get().startPlugin(id);
            return true;
        }
        return false;
    }

    @Override
    public boolean updatePlugin(String id, String url) {
        return false;
    }

    @Override
    public boolean uninstallPlugin(String id) {
        return super.uninstallPlugin(id);
    }
}